#include <stdio.h>
#include <stdbool.h>

#include "freertos.h"
#include "task.h"

#include "bms_type.h"
#include "bms_global.h"

#include "bms_monitor.h"
#include "bms_energy.h"

/* thread config */
#define MONITOR_TASK_STACK_SIZE	128
#define MONITOR_TASK_PRIORITY	  4
#define MONITOR_TASK_PERIOD		  250

#define UPDATE_CELL_VOLTAGE_CYCLE	250
#define UPDAYE_BAT_VOLTAGE_CYCLE	250
#define UPDATE_CELL_TEMP_CYCLE		2000
#define UPDATE_BAT_CURRENT_CYCLE	1000

BMS_MonitorDataTypedef BMS_MonitorData; /* = {
	.isChMosOpen  = false;
	.isDisMosOpen = false;
}; */

static bool FlagSampleIntCur    = false;

static bool FlagCellVoltage     = true;
static bool FlagBatVoltage      = true;
static bool FlagCellTemp        = true;
static bool FlagBatCurrent      = true;


static uint16_t CountCellVoltage = 0;
static uint16_t CountBatVoltage = 0;
static uint16_t CountCellTemp = 0;

static TaskHandle_t MonitorTaskHandler = NULL;  

static void BMS_MonitorTaskEntry(void *paramter);
static void BMS_MonitorBattery();
static void BMS_MonitorSysMode();

void BMS_MonitorInit(void)
{
	BaseType_t res = xTaskCreate(BMS_MonitorTaskEntry,                    
								 "monitor",                  
								 MONITOR_TASK_STACK_SIZE,                         
								 NULL,                        
								 MONITOR_TASK_PRIORITY,                           
								 &MonitorTaskHandler);  
	
	if(res != pdPASS)
	{
		printf("Create Monitor Task Fail\r\n");
	}
}

static void BMS_MonitorTaskEntry(void *paramter)
{
	while(1)
	{
		BMS_MonitorBattery();
		BMS_MonitorSysMode();
		vTaskDelay(pdMS_TO_TICKS(MONITOR_TASK_PERIOD));
	}
}

static void BMS_MonitorBattery(void)
{
	/* 采集单体电压 */
	CountCellVoltage += MONITOR_TASK_PERIOD;
	if(FlagCellVoltage == true && CountCellVoltage >= UPDATE_CELL_VOLTAGE_CYCLE)
	{
		Bms_HalMonitorCellVoltage();
		CountCellVoltage = 0;	
	}
	else
	{
		CountCellVoltage = 0;
	}
	
	/* 采集电池总压 */
	CountBatVoltage += MONITOR_TASK_PERIOD;
	if(FlagBatVoltage == true && CountBatVoltage >= UPDAYE_BAT_VOLTAGE_CYCLE)
	{
		BMS_HalMonitorBatteryVoltage();
		CountBatVoltage = 0;
	}
	else
	{
		CountBatVoltage = 0;
	}
	
	/* 采集 NTC 温度 */
	CountCellTemp += MONITOR_TASK_PERIOD;
	if(FlagCellTemp == true && CountCellTemp >= UPDATE_CELL_TEMP_CYCLE)
	{
		BMS_HALMonitorCellTemperature();
		FlagCellTemp = 0;
	}
	else
	{
		FlagCellTemp = 0;
	}
	
	/* 采集电流 */
	// if(FlagSampleIntCur == true && FlagBatCurrent == true)
	{
		Bms_HalMonitorBatteryCurrent();
		FlagSampleIntCur = false;
	}
	
	/* Get mos status */
	BQ769X0_IsMosOpen( &BMS_MonitorData.isChMosOpen, &BMS_MonitorData.isDisMosOpen );
}

// BatteryCurrent > 20mA || BatteryCurrent < -20mA Enter standby mode condition (neither charging nor discharging)
// BatteryCurrent < 20mA || BatteryCurrent > -20mA The battery is in standby or sleep mode
// BatteryCurrent <= -20mA The battery is in discharge mode
// BatteryCurrent >=  20mA The battery is in charge mode
void BMS_MonitorSysMode(void)
{
	static BMS_SysModeTypedef SysModeBack = BMS_MODE_NULL;
	static uint32_t StandbyCount = 0;
	
	// weak up, sleep mode -> standby mode
	if(BMS_GlobalParam.SysMode == BMS_MODE_SLEEP 
			&& (BMS_MonitorData.BatteryCurrent >= 0.02 || BMS_MonitorData.BatteryCurrent <= -0.02))
	{
		BMS_GlobalParam.SysMode = BMS_MODE_STANDBY;
		printf("[[[[ Weak Up ]]]]\r\n");
	}
	
	// If you stay in standby mode for a long time and the balance condition is not satisfied, switch to sleep mode
	if(BMS_MonitorData.BatteryCurrent < 0.02 && BMS_MonitorData.BatteryCurrent > -0.02)
	{
		BMS_GlobalParam.SysMode = BMS_MODE_STANDBY;
		
		if(SysModeBack != BMS_MODE_STANDBY)
		{
			SysModeBack = BMS_MODE_STANDBY;
			printf("<<<<<<<< Enter Standby Mode >>>>>>>>\r\n");
		}
		
		if(StandbyCount >= BMS_ENTRY_SLEEP_TIME * 60000 && BMS_EnergyData.BalanceReleaseFlag != true)
		{
			StandbyCount = 0;
			BMS_GlobalParam.SysMode = BMS_MODE_SLEEP;
			printf("[[[[ Enter Sleep Mode ]]]]\r\n");
		}
		else
		{
			StandbyCount += MONITOR_TASK_PERIOD;
		}
	}
	
	// Charging current > 20mA, no matter what the original mode, immediately converted to charging mode
	else if(BMS_MonitorData.BatteryCurrent >= 0.02)
	{
		StandbyCount = 0;
		BMS_GlobalParam.SysMode = BMS_MODE_CHARGE;
		
		if(SysModeBack != BMS_MODE_CHARGE)
		{
			SysModeBack = BMS_MODE_CHARGE;
			printf("<<<<<<<< Enter Charge Mode >>>>>>>> \r\n");
		}
	}
	
	else if(BMS_MonitorData.BatteryCurrent <= -0.02)
	{
		StandbyCount = 0;
		BMS_GlobalParam.SysMode = BMS_MODE_DISCHARGE;
		if(SysModeBack != BMS_MODE_DISCHARGE)
		{
			SysModeBack = BMS_MODE_DISCHARGE;
			printf("<<<<<<<< Enter Discharge Mode >>>>>>>> \r\n");
		}
	}
}

/**
 * @brief Coulomb meter current sampling completion callback.
 */
void BMS_MonitorHwCurrent( void )
{
	FlagSampleIntCur = true;
}